package com.eunion.web.common.controller;

import java.io.IOException;
import java.sql.SQLException;

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.eunion.core.exception.ExceptionVo;
import com.eunion.core.exception.ProjectException;
import com.eunion.core.exception.json.JsonException;
import com.eunion.core.exception.json.JsonInvalidException;
import com.eunion.core.exception.json.JsonNotFoundException;
import com.eunion.core.exception.page.PageDatabaseException;
import com.eunion.core.exception.page.PageException;
import com.eunion.core.exception.page.PageInvalidException;
import com.eunion.core.exception.page.PageNotFoundException;

/**
 * http://docs.spring.io/spring/docs/4.2.1.RELEASE/spring-framework-reference/ htmlsingle/#mvc-exceptionhandlers
 * @version 2015-9-9
 */
@Controller
public class ErrorController {

	// protected Logger LOGGER = LoggerFactory.getLogger(getClass());

	// @RequestMapping(value = "/error", produces = "application/json")
	// @ResponseBody
	// public Map<String, Object> handle(HttpServletRequest request)
	// {
	//
	// Map<String, Object> map = new HashMap<String, Object>();
	// map.put("status",
	// request.getAttribute("javax.servlet.error.status_code"));
	// map.put("reason", request.getAttribute("javax.servlet.error.message"));
	//
	// return map;
	// }

	/**
	 * error/{id} 根据id抛出异常.
	 */
	@RequestMapping(value = "/error/{id}", method = RequestMethod.GET)
	public String getEmployee(@PathVariable("id") int id, Model model)
	    throws Exception {
		// deliberately throwing different types of exception
		if (id == 1) {
			throw new PageNotFoundException("PageNotFoundException,id=" + String.valueOf(id));
		} else if (id == 2) {
			throw new PageDatabaseException("PageDatabaseException, id=" + id);
		} else if (id == 3) {
			throw new PageInvalidException("PageInvalidException, id=" + id);
		} else if (id == 4) {
			throw new PageException("PageException, id=" + id);
		} else if (id == 11) {
			throw new JsonInvalidException("JsonInvalidException, id=" + id);
		} else if (id == 12) {
			throw new JsonNotFoundException("JsonNotFoundException, id=" + id);
		} else if (id == 13) {
			throw new JsonException("JsonException, id=" + id);
		} else if (id == 21) {
			throw new SQLException("ExceptionGlobalHandler SQLException, id=" + id);
		} else if (id == 22) {
			throw new IOException("ExceptionGlobalHandler IOException, id=" + id);
		} else if (id == 23) {
			throw new SQLException("ExceptionGlobalHandler SQLException, id=" + id);
		} else if (id == 0) {
			throw new ProjectException("WebException, id=" + id);
		} else {
			throw new Exception("Exception, id=" + id);
		}
	}

	// @ExceptionHandler(IOException.class)
	// public ResponseEntity<String> handleIOException(IOException ex)
	// {
	// ResponseEntity<String> re = new
	// ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
	// return re;
	// }

	/**
	 * PageNotFoundException e-404.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(value = {PageNotFoundException.class})
	public ModelAndView notFoundException(HttpServletRequest request, Exception ex) {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("exception", ex);
		modelAndView.addObject("url", request.getRequestURL());
		modelAndView.setViewName("e-404");
		return modelAndView;
	}

	/**
	 * PageDatabaseException e-500.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(value = {PageDatabaseException.class})
	public ModelAndView pageDatabaseException(HttpServletRequest request, Exception ex) {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("exception", ex);
		modelAndView.addObject("url", request.getRequestURL());
		modelAndView.setViewName("e-500");
		return modelAndView;
	}

	/**
	 * PageInvalidException e-error.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(value = {PageInvalidException.class})
	public ModelAndView pageInvalidException(HttpServletRequest request, Exception ex) {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("exception", ex);
		modelAndView.addObject("url", request.getRequestURL());
		modelAndView.setViewName("e-error");
		return modelAndView;
	}

	/**
	 * PageException e-exception.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(value = {PageException.class})
	public ModelAndView pageException(HttpServletRequest request, Exception ex) {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("exception", ex);
		modelAndView.addObject("url", request.getRequestURL());
		modelAndView.setViewName("e-exception");
		return modelAndView;
	}

	/**
	 * jsonInvalidException ResponseBody.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(JsonInvalidException.class)
	@ResponseBody
	public ExceptionVo jsonInvalidException(HttpServletRequest request, Exception ex) {
		ExceptionVo response = new ExceptionVo();
		response.setUrl(request.getRequestURL().toString());
		response.setMessage(ex.getMessage());
		return response;
	}

	/**
	 * JsonNotFoundException ResponseEntity status NOT_FOUND.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler// (org.apache.shiro.authz.UnauthorizedException.class)
	public ResponseEntity<String> forbiddenException(HttpServletRequest request, Exception ex) {
		return new ResponseEntity<String>("访问受限的资源，请确保您已获取过授权 (403 forbidden)", HttpStatus.FORBIDDEN);
	}

	/**
	 * JsonNotFoundException ResponseEntity status NOT_FOUND.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(JsonNotFoundException.class)
	public ResponseEntity<String> jsonNotFoundException(HttpServletRequest request, Exception ex) {
		return new ResponseEntity<String>("The String ResponseBody with custom status code (404 Not Found)", HttpStatus.NOT_FOUND);
	}

	/**
	 * handleJsonReqException ResponseEntity TEXT_PLAIN.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(JsonException.class)
	public ResponseEntity<String> handleJsonReqException(HttpServletRequest request, Exception ex) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.TEXT_PLAIN);
		return new ResponseEntity<String>("The String ResponseBody with custom header Content-Type=text/plain", headers, HttpStatus.OK);
	}

	/**
	 * handleJsonException ResponseEntity APPLICATION_JSON.
	 * @param request
	 * @param ex
	 * @return
	 */
	@ExceptionHandler(ProjectException.class)
	public ResponseEntity<String> handleJsonException(HttpServletRequest request, Exception ex) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		return new ResponseEntity<String>("The String ResponseBody with custom header Content-Type=text/plain", headers, HttpStatus.OK);
	}

	// //https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
	// // Convert a predefined exception to an HTTP Status code
	// @ResponseStatus(value=HttpStatus.CONFLICT, reason="Data integrity violation") // 409
	// @ExceptionHandler(DataIntegrityViolationException.class)
	// public void conflict() {
	// // Nothing to do
	// }
	//
	// // Specify the name of a specific view that will be used to display the error:
	// @ExceptionHandler({SQLException.class,DataAccessException.class})
	// public String databaseError() {
	// // Nothing to do. Returns the logical view name of an error page, passed to
	// // the view-resolver(s) in usual way.
	// // Note that the exception is _not_ available to this view (it is not added to
	// // the model) but see "Extending ExceptionHandlerExceptionResolver" below.
	// return "databaseError";
	// }
	//
	// // Total control - setup a model and return the view name yourself. Or consider
	// // subclassing ExceptionHandlerExceptionResolver (see below).
	// @ExceptionHandler(Exception.class)
	// public ModelAndView handleError(HttpServletRequest req, Exception exception) {
	// logger.error("Request: " + req.getRequestURL() + " raised " + exception);
	//
	// ModelAndView mav = new ModelAndView();
	// mav.addObject("exception", exception);
	// mav.addObject("url", req.getRequestURL());
	// mav.setViewName("error");
	// return mav;
	// }
}
